package com.test.concurrency.waxomatic;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

class Car {
	private boolean waxOn = false;

	public synchronized void waxed() {
		waxOn = true;// Ready to buff
		notifyAll();
	}

	public synchronized void buffed() {
		waxOn = false; // ready for another coat of wax;
		notifyAll();
	}

	public synchronized void waitingForWaxing() throws InterruptedException {
		while(waxOn==false){
			wait();
		}
	}
	public synchronized void waitingForBuffing()throws InterruptedException{
		while(waxOn==true){
			wait();
		}
	}
}

class WaxOn implements Runnable{
	private Car car;
	public WaxOn(Car c){
		car =c;
	}
	@Override
	public void run() {
		try {
			//while loop is to prevent from deadlock
			while(!Thread.interrupted()){
				System.out.println("Wax on! ");
				TimeUnit.MILLISECONDS.sleep(200);
				car.waxed();
				car.waitingForBuffing();
			}
		} catch (Exception e) {
			System.out.println("Exiting via interrupt");
		}
		System.out.println("Ending Wax On task");
	}
	
}
class WaxOff implements Runnable{
	private Car car;
	public WaxOff(Car c){
		car =c;
	}
	@Override
	public void run() {
		try {
			while(!Thread.interrupted()){
				car.waitingForWaxing();
				System.out.println("Wax  off! ");
				TimeUnit.MILLISECONDS.sleep(200);
				car.buffed();
			}
		} catch (Exception e) {
			System.out.println("Exiting via interrupt");
		}
		System.out.println("Ending Wax off task ");
	}
	
}
/**
 * The only place you can call wait(),notify(),or notifyAll() is within a
 * synchronized method or block,because before you call them they must own the
 * lock for the object since they release the lock
 * 
 * @author Administrator
 * 
 */
public class WaxOMatic {
	public static void main(String[] args) throws Exception{
		Car car = new Car();
		ExecutorService exec = Executors.newCachedThreadPool();
		exec.execute(new WaxOff(car));
		exec.execute(new WaxOn(car));
		TimeUnit.SECONDS.sleep(5);//run for a while...
		exec.shutdownNow();//interrupt all task
	}

}
